import pandas as pd
import time
import threading
from collections import defaultdict
import sys


# 发送函数保持不变
def send_command(can, send_id, data):
    frame_num = 0
    #判断发送缓冲区的第几个是空的
    for i in can.sendbuf:
        if i.ID != 0x0:
            frame_num += 1

    can.sendbuf[frame_num].ID = send_id
    #设置扩展帧的标志位，否则会以标准帧发送
    if send_id > 0x7FF:
        can.sendbuf[frame_num].ExternFlag = True
    send_len = len(data)
    if send_len == 8:
        can.sendbuf[frame_num].setdata(data)
    else:
        can.sendbuf[frame_num].DataLen = send_len
        for i in range(send_len):
            can.sendbuf[frame_num].Data[i] = data[i]

    can.transmit()


class CAN_Scheduler:
    def __init__(self, p_can):
        self.p_can = p_can  # 使用外部传入的can_handle
        self.running = True
        self.lock = threading.Lock()
        # 存储每个ID的最后发送时间
        self.id_last_send = defaultdict(float)
        # 存储每个ID的数据列表
        self.id_data = {}
        # 存储每个ID的当前发送索引
        self.id_index = defaultdict(int)

        # 初始化缓冲区统计属性（修复AttributeError）
        self.buffer_usage = 0
        self.max_buffer_usage = 0

        # 发送线程
        self.send_thread = threading.Thread(target=self._sending_thread, name="_sending_thread")
        self.send_thread.daemon = True
        self.send_thread.start()

        # 缓冲区监控线程
        self.buffer_thread = threading.Thread(target=self._buffer_monitor, name="_buffer_monitor")
        self.buffer_thread.daemon = True
        self.buffer_thread.start()

    def add_id_data(self, frame_id, data_list):
        """添加ID及其数据列表"""
        with self.lock:
            self.id_data[frame_id] = data_list
            self.id_index[frame_id] = 0
            self.id_last_send[frame_id] = 0.0

    def _buffer_monitor(self):
        """监控缓冲区使用情况"""
        while self.running:
            try:
                # 检查缓冲区使用率
                used = sum(1 for frame in self.p_can.sendbuf if frame.ID != 0x0)
                buffer_usage = used / len(self.p_can.sendbuf)

                with self.lock:
                    self.buffer_usage = buffer_usage
                    self.max_buffer_usage = max(self.max_buffer_usage, buffer_usage)

                # 如果缓冲区接近满，降低发送速率
                if buffer_usage > 0.7:
                    time.sleep(0.005)  # 额外等待5ms

                time.sleep(0.01)  # 每10ms检查一次
            except Exception as e:
                print(f"缓冲区监控错误: {e}")
                time.sleep(0.1)

    def _sending_thread(self):
        """发送线程主循环"""
        while self.running:
            try:
                with self.lock:
                    current_time = time.time()

                    # 1. 查找可以发送的ID
                    send_candidate = None
                    min_wait_time = float('inf')  # 初始化为最大值

                    for frame_id in list(self.id_data.keys()):
                        # 计算该ID距离上次发送的时间
                        last_send = self.id_last_send[frame_id]
                        if last_send == 0.0:  # 从未发送过
                            send_candidate = frame_id
                            min_wait_time = 0
                            break

                        id_interval = (current_time - last_send) * 1000  # 毫秒

                        # 如果满足100ms间隔
                        if id_interval >= 100:
                            send_candidate = frame_id
                            min_wait_time = 0
                            break

                        # 计算还需要等待的时间
                        wait_time = 100 - id_interval
                        if wait_time < min_wait_time:
                            min_wait_time = wait_time
                            send_candidate = frame_id

                # 2. 如果没有找到可发送的ID，等待最小等待时间
                if send_candidate is None:
                    # 如果没有ID，等待100ms后重试
                    time.sleep(0.1)
                    continue

                # 3. 等待适当时间
                if min_wait_time > 0:
                    # 添加少量间隔防止缓冲区溢出
                    actual_wait = min(min_wait_time, 10)  # 最多等待10ms
                    time.sleep(actual_wait / 1000.0)

                # 4. 发送消息
                with self.lock:
                    # 获取要发送的数据
                    if send_candidate not in self.id_data:
                        continue  # ID可能已被移除

                    data_list = self.id_data[send_candidate]
                    idx = self.id_index[send_candidate]
                    data = data_list[idx]

                    # 更新索引（循环）
                    self.id_index[send_candidate] = (idx + 1) % len(data_list)

                    # 更新发送时间
                    self.id_last_send[send_candidate] = time.time()

                # 发送消息（使用外部传入的p_can）
                send_command(self.p_can, send_candidate, data)

                # 5. 添加少量间隔防止缓冲区溢出
                time.sleep(0.001)  # 1ms间隔

            except Exception as e:
                print(f"发送线程错误: {e}")
                time.sleep(0.1)

    def stop(self):
        """停止发送线程"""
        self.running = False
        self.send_thread.join(timeout=1.0)
        self.buffer_thread.join(timeout=0.5)
        print(f"发送线程已停止，最大缓冲区使用率: {self.max_buffer_usage * 100:.1f}%")


def read_can_data_from_excel(file_path):
    """
    读取Excel文件中的CAN数据，按帧ID分组存储
    """
    try:
        df = pd.read_excel(file_path)
    except Exception as e:
        print(f"读取Excel文件失败: {e}")
        return {}

    # 检查必要的列是否存在
    required_columns = ['帧ID', '数据(HEX)']
    for col in required_columns:
        if col not in df.columns:
            print(f"Excel文件中缺少必要的列: '{col}'")
            return {}

    # 使用defaultdict创建自动初始化的字典
    id_data_dict = defaultdict(list)

    # 遍历每一行数据
    for index, row in df.iterrows():
        frame_id = row['帧ID']

        # 处理帧ID格式
        try:
            if isinstance(frame_id, str):
                if frame_id.startswith('0x'):
                    frame_id = int(frame_id[2:], 16)
                else:
                    frame_id = int(frame_id)
            elif isinstance(frame_id, int):
                pass  # 已经是整数
            else:
                print(f"跳过无效的帧ID类型: {type(frame_id)}")
                continue
        except Exception as e:
            print(f"转换帧ID失败: {frame_id}, 错误: {e}")
            continue

        hex_data = row['数据(HEX)']

        # 添加到对应ID的列表中
        id_data_dict[frame_id].append(hex_data)

    return dict(id_data_dict)


def hex_str_to_byte_list(hex_str):
    """
    将十六进制字符串转换为字节列表
    """
    try:
        # 移除空格并确保长度为偶数
        clean_hex = hex_str.replace(" ", "").strip()
        if len(clean_hex) == 0:
            return []

        if len(clean_hex) % 2 != 0:
            # 尝试修复奇数长度的十六进制字符串
            clean_hex = '0' + clean_hex

        # 每两个字符转换为一个字节
        byte_list = []
        for i in range(0, len(clean_hex), 2):
            byte_str = clean_hex[i:i + 2]
            byte_list.append(int(byte_str, 16))

        return byte_list
    except Exception as e:
        print(f"转换十六进制字符串失败: '{hex_str}', 错误: {e}")
        return []


def bytes_to_hex(byte_list):
    """将字节列表转换为十六进制字符串"""
    return " ".join(f"{b:02X}" for b in byte_list)


